package com.panda.system.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.panda.common.core.domain.AjaxResult;
import com.panda.common.core.domain.entity.SysUser;
import com.panda.common.core.domain.model.LoginUser;
import com.panda.common.utils.DateUtils;
import com.panda.common.utils.ServletUtils;
import com.panda.common.utils.spring.SpringUtils;
import com.panda.framework.web.service.TokenService;
import com.panda.system.common.constant.Constants;
import com.panda.system.common.constant.EnumConstants;
import com.panda.system.domain.*;
import com.panda.system.dto.DistributionTaskDto;
import com.panda.system.dto.TaskFpDto;
import com.panda.system.mapper.PandaTaskMapper;
import com.panda.system.service.*;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 任务信息Service业务层处理
 * 
 * @author ruoyi
 * @date 2021-01-02
 */
@Service
@Transactional
public class PandaTaskServiceImpl implements IPandaTaskService 
{
    private static final Logger log = LoggerFactory.getLogger(IPandaTaskService.class);
    @Autowired
    private PandaTaskMapper pandaTaskMapper;

    @Autowired
    private IPandaStoreService iPandaStoreService;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private IPandaTaskMonitoringService taskMonitoringService;

    @Autowired
    private IPandaWorkbenchService workbenchService;

    @Autowired
    private ITPandaTaskUserService taskUserService;

    /**
     * 查询任务信息
     * 
     * @param taskId 任务信息ID
     * @return 任务信息
     */
    @Override
    public PandaTask selectPandaTaskById(Long taskId)
    {
        return pandaTaskMapper.selectPandaTaskById(taskId);
    }

    /**
     * 查询任务信息列表
     * 
     * @param pandaTask 任务信息
     * @return 任务信息
     */
    @Override
    public List<PandaTask> selectPandaTaskList(PandaTask pandaTask)
    {
        log.info("查询任务列表，入参：{}",pandaTask);
        return pandaTaskMapper.selectPandaTaskList(pandaTask);
    }

    /**
     * 新增任务信息
     * 
     * @param pandaTask 任务信息
     * @return 结果
     */
    @Override
    public AjaxResult insertPandaTask(PandaTask pandaTask)
    {
        pandaTask.setCreateTime(DateUtils.getNowDate());
        List<PandaStore> pandaStores = iPandaStoreService.selectPandaStoreListByNames(Arrays.asList(pandaTask.getStoreName()));
        if(pandaStores.size()==0){
            return AjaxResult.error("未查询到店铺信息，请先新增店铺！");

        }
        pandaTask.setStoreId(pandaStores.get(0).getStoreId());
        if(pandaTask.getDailyTradingVolume() ==null){
            pandaTask.setDailyTradingVolume(0);
        }
        if(pandaTask.getReservedTradingVolume() ==null){
            pandaTask.setReservedTradingVolume(0);
        }
        // 设置初始值
        pandaTask.setStatus(EnumConstants.TaskType.NEW_CREATE.getCode());
        pandaTask.setRemainVolume(pandaTask.getDailyTradingVolume()+pandaTask.getReservedTradingVolume());
        pandaTask.setCreateTime(new Date());
        int id = pandaTaskMapper.insertPandaTask(pandaTask);

        return AjaxResult.success("保存成功！",pandaTask) ;
    }

    /**
     * 修改任务信息
     * 
     * @param pandaTask 任务信息
     * @return 结果
     */
    @Override
    public int updatePandaTask(PandaTask pandaTask)
    {
        pandaTask.setUpdateTime(DateUtils.getNowDate());
        return pandaTaskMapper.updatePandaTask(pandaTask);
    }

    /**
     * 批量删除任务信息
     * 
     * @param taskIds 需要删除的任务信息ID
     * @return 结果
     */
    @Override
    public AjaxResult deletePandaTaskByIds(Long[] taskIds)
    {
        List<String> status = new ArrayList<>();
        status.add(EnumConstants.TaskType.BEEN_OPERATING.getCode());
        status.add(EnumConstants.TaskType.HAVE_ORDER.getCode());
        status.add(EnumConstants.TaskType.COMPLETE.getCode());

        // 判断
        for(long id:taskIds){
            PandaTask task = selectPandaTaskById(id);
            if(status.contains(task.getStatus())){
                return AjaxResult.error("删除任务失败！任务id："+id+",存在已完成任务！");
            }
            TPandaTaskUser tPandaTaskUser = new TPandaTaskUser();
            tPandaTaskUser.setLinkId(Long.toString(id));
            List<TPandaTaskUser> tPandaTaskUsers = taskUserService.selectTPandaTaskUserList(tPandaTaskUser);
            if(!CollectionUtils.isEmpty(tPandaTaskUsers)){
                List<Long> idList = tPandaTaskUsers.stream().map(TPandaTaskUser::getId).collect(Collectors.toList());
                taskUserService.deleteTPandaTaskUserByIds(idList.toArray(new Long[0]));
            }
        }
        pandaTaskMapper.deletePandaTaskByIds(taskIds);

        return AjaxResult.success("删除任务成功！");
    }

    /**
     * 删除任务信息信息
     * 
     * @param taskId 任务信息ID
     * @return 结果
     */
    @Override
    public int deletePandaTaskById(Long taskId)
    {
        return pandaTaskMapper.deletePandaTaskById(taskId);
    }

    /**
     * 任务信息导入
     * @param list 任务信息ID
     * @return
     */
    @Override
    public AjaxResult importTask(List<PandaTask> list) {
        if(CollectionUtils.isEmpty(list)){
            return AjaxResult.error("导入任务列表为空！");
        }
        // 获取任务对应的店铺信息
        List<String> storeNames = list.stream().map(PandaTask::getStoreName).collect(Collectors.toList());
        Set<String> nameSet = new HashSet<>(storeNames);
        List<PandaStore> pandaStores = iPandaStoreService.selectPandaStoreListByNames(storeNames);
        if(CollectionUtils.isEmpty(pandaStores)){
            return AjaxResult.error("店铺信息不存在，请维护！");
        }
        if(!CollectionUtils.isEmpty(pandaStores)){
            List<String> names = pandaStores.stream().map(PandaStore::getStoreName).collect(Collectors.toList());
            // 去重
            nameSet.removeIf(item->names.contains(item));
        }
        // 新增店铺
        nameSet.forEach(item->{
            item.trim();
            PandaStore store = new PandaStore(item);
            int id = iPandaStoreService.insertPandaStore(store);
            store.setStoreId(Long.valueOf(id));
            pandaStores.add(store);
        });
        Map<String,PandaStore> storeMap = new HashMap<>();
        pandaStores.forEach(item->storeMap.put(item.getStoreName(),item));
        List<PandaTask> errorList = new ArrayList<>();
        list.forEach(task->{
            if(Strings.isEmpty(task.getStoreName())){
                // 店铺为空
                errorList.add(task);
                return;
            }
            PandaStore store = storeMap.get(task.getStoreName());
            task.setStatus(EnumConstants.TaskType.NEW_CREATE.getCode());
            task.setStoreId(store.getStoreId());
            task.setRemainVolume(task.getDailyTradingVolume()+task.getReservedTradingVolume());
            task.setCreateTime(new Date());
            pandaTaskMapper.insertPandaTask(task);
        });
        String errorListMsg = errorList.size()>0? JSONUtils.toJSONString(errorList) :"";
        return AjaxResult.success("导入任务列表完成！总记录数："+list.size()+",失败记录数："+errorList.size()+"!"+errorListMsg);
    }

    @Override
    public AjaxResult distributionTask(DistributionTaskDto distributionTaskDto) {
        if(Strings.isEmpty(distributionTaskDto.getUserId())&& Strings.isEmpty(distributionTaskDto.getDeptId())){
            return AjaxResult.error("分配任务失败，请选择用户/部门！");
        }
        if(CollectionUtils.isEmpty(distributionTaskDto.getTaskIds())){
            return AjaxResult.error("分配任务失败，请选择待分配任务！");
        }
        List<PandaTask> pandaTasks = pandaTaskMapper.selectPandaTaskListByIds(distributionTaskDto.getTaskIds());
        if(CollectionUtils.isEmpty(pandaTasks)){
            return AjaxResult.error("分配任务失败，请选择待分配/新建任务！");
        }
        // 分配到人
        if(!Strings.isEmpty(distributionTaskDto.getUserId())){
            SysUser sysUser = iSysUserService.selectUserById(Long.valueOf(distributionTaskDto.getUserId()));
            if(sysUser ==null){
                return AjaxResult.error("分配任务失败，用户不存在！");
            }
            distributionTaskToUser(sysUser,pandaTasks);
        }else if(!Strings.isEmpty(distributionTaskDto.getDeptId())){
            // 分配到部门
            List<SysUser> userList = getUserList(distributionTaskDto);
            if(CollectionUtils.isEmpty(userList)){
                AjaxResult.error("操作员配置为空，请联系管理员配置！");
            }
            // 任务均分
            // 任务按时间分组
            Map<Date,List<PandaTask>> stringListMap = pandaTasks.stream().collect(Collectors.groupingBy(PandaTask::getTastDate));
            for(Date date:stringListMap.keySet()){
                List<PandaTask> pandaTasksOne = stringListMap.get(date);
                distributionTaskToUsers(userList,pandaTasksOne);
            }

        }

        return AjaxResult.success("分配任务成功！");
    }

    private List<SysUser> getUserList(DistributionTaskDto distributionTaskDto){
        SysUser sysUser = new SysUser();
        sysUser.setDeptId(Long.valueOf(distributionTaskDto.getDeptId()));
        List<SysUser> sysUsers = iSysUserService.selectUserListBySys(sysUser);
        // 获取多有可分配的用户 通过岗位编码匹配
        List<SysUser> sysUsers1 = iSysUserService.selectUserListByPostCodes(Arrays.asList(Constants.OPERATOR_USER),
                sysUsers.stream().map(SysUser::getUserId).collect(Collectors.toList()));
        return sysUsers1;
    }

    private List<SysUser> sortUser(List<SysUser> sysUsers1,String type,Date startTime){
        // 获取所有已分配任务列表
        TPandaTaskUser tPandaTaskUser = new TPandaTaskUser();
        tPandaTaskUser.setStatus(EnumConstants.SysStatus.OPEN.getCode());
        tPandaTaskUser.setTastDate(startTime);
        List<TPandaTaskUser> tPandaTaskUsers = taskUserService.selectTPandaTaskUserList(tPandaTaskUser);
        Map<Long,List<TPandaTaskUser>> tPandaTaskUserMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(tPandaTaskUsers)){
            tPandaTaskUserMap = tPandaTaskUsers.stream().collect(Collectors.groupingBy(TPandaTaskUser::getResponsibleUserId));
        }
        List<TaskFpDto> taskFpDtos = new ArrayList<>();
        for(SysUser user:sysUsers1){
            TaskFpDto taskFpDto = new TaskFpDto();
            List<TPandaTaskUser> tPandaTaskUsers1 = tPandaTaskUserMap.get(user.getUserId());
            int count = 0 ;
            if(!CollectionUtils.isEmpty(tPandaTaskUsers1)){
                for(TPandaTaskUser taskUser:tPandaTaskUsers1){
                    count+=taskUser.getDailyTradingVolume();
                    count+=taskUser.getReservedTradingVolume();
                }
            }
            taskFpDto.setUserId(user.getUserId());
            taskFpDto.setTaskCount(count);
            taskFpDtos.add(taskFpDto);
        }
        Map<Long,SysUser> userMap = new HashMap<>();
        sysUsers1.forEach(item->userMap.put(item.getUserId(),item));
        if(!CollectionUtils.isEmpty(taskFpDtos)){
            // 排序 正序
            taskFpDtos.sort(TaskFpDto::compare);
        }
        List<SysUser> result = new ArrayList<>();
        for(TaskFpDto taskFpDto:taskFpDtos){
            SysUser user = userMap.get(taskFpDto.getUserId());
            result.add(user);
        }
        return result;
    }

    @Override
    public boolean checkTodoTask(Long taskId) {
        PandaTask task = pandaTaskMapper.selectPandaTaskById(taskId);
        if(task.getRemainVolume()>0){
            return true;
        }
        return false;
    }

    @Override
    public void failureTask(List<PandaTask> list) {
        // 删除分配任务
        List<Long> taskIdList = list.stream().map(PandaTask::getTaskId).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(taskIdList)){
            Long[] ids = taskIdList.toArray(new Long[0]);
            List<TPandaTaskUser> userTasks = taskUserService.getUserTaskListByParentTaskIds(taskIdList);
            List<Long> userTaskIds = userTasks.stream().map(TPandaTaskUser::getId).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(userTaskIds)){
                taskUserService.deleteTPandaTaskUserByIds(userTaskIds.toArray(new Long[0]));
            }
            pandaTaskMapper.deletePandaTaskByIds(ids);
        }

    }

    private void distributionTaskToUser(SysUser sysUser,List<PandaTask> pandaTasks){
        pandaTasks.forEach(item->{
            // 生成待办
            createTodo(item,sysUser);
            // 修改任务信息
            pandaTaskMapper.updatePandaTaskStatus(item.getTaskId(),EnumConstants.TaskType.BE_DISTRIBUTED.getCode());
            // 记录分配时间
            // 获取当前的用户
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
            PandaTaskMonitoring monitoring = new PandaTaskMonitoring();
            monitoring.setOperationTime(new Date());
            monitoring.setOperationType(EnumConstants.OperationType.DISTRIBUTION.getCode());
            monitoring.setOperationUserId(loginUser.getUser().getUserId());
            monitoring.setTaskId(item.getTaskId());
            taskMonitoringService.insertPandaTaskMonitoring(monitoring);
        });
    }

    private void distributionTaskToUsers(List<SysUser> sysUsers,List<PandaTask> pandaTasks){
        AtomicReference<Integer> dailyTradingTodo = new AtomicReference<>(0);
        AtomicReference<Integer> reservedTradingTodo = new AtomicReference<>(0);
        AtomicReference<Date> nowDate = new AtomicReference<Date>();
        pandaTasks.forEach(item-> {
            nowDate.set(item.getTastDate());
            dailyTradingTodo.updateAndGet(v -> v + item.getDailyTradingVolume());
            reservedTradingTodo.updateAndGet(v -> v + item.getReservedTradingVolume());
        });
        // 用户按当天 任务量排序 升序
        sysUsers = sortUser(sysUsers,"ACS",nowDate.get());

        // 均值
        Integer dailyAverage = dailyTradingTodo.get()/sysUsers.size();
        Integer reservedAverage = reservedTradingTodo.get()/sysUsers.size();

        // 余量
        Integer dailyAllowance = dailyTradingTodo.get()%sysUsers.size();
        Integer reservedAllowance = reservedTradingTodo.get()%sysUsers.size();

        if(dailyTradingTodo.get()>0&&dailyAverage==0){
            dailyAverage =1;
            // 任务量不足均分时，余量置为0
            dailyAllowance = 0;
        }
        if(reservedTradingTodo.get()>0&&reservedAverage==0){
            reservedAverage =1;
            // 任务量不足均分时，余量置为0
            reservedAllowance = 0;
        }
        if(reservedTradingTodo.get()==0&&dailyTradingTodo.get()==0){
            return;
        }

        int i=0;
        List<PandaTask> dayTasksAll = new ArrayList<>(pandaTasks);
        List<PandaTask> reservedTasksAll = new ArrayList<>(pandaTasks);
        for(SysUser user:sysUsers){
            i++;
            int dailyTodo = dailyAverage;
            if(dailyAllowance>0){
                dailyTodo+=1;
                dailyAllowance--;
            }
            int reserveddo = reservedAverage;
            if(reservedAllowance>0){
                reserveddo+=1;
                reservedAllowance--;
            }
            List<PandaTask> tasks = new ArrayList<>();
            List<PandaTask> reserveTasks = new ArrayList<>();
            List<PandaTask> dayTasks = new ArrayList<>(dayTasksAll);
            for(PandaTask day:dayTasks){
                if(dailyTodo<=0){
                    break;
                }
                if(day.getDailyTradingVolume()<=0){
                    continue;
                }
                PandaTask task =  new PandaTask();
                task = JSON.parseObject(JSON.toJSONBytes(day),PandaTask.class);

                task.setReservedTradingVolume(0);
                if(task.getDailyTradingVolume()>dailyTodo){
                    task.setFpValue(dailyTodo);
                    tasks.add(task);
                    int finalDailyTodo = dailyTodo;
                    dayTasksAll.forEach(item->{
                        if(item.getTaskId().equals(day.getTaskId()) ){
                            item.setDailyTradingVolume(day.getDailyTradingVolume()- finalDailyTodo);
                        }
                    });
                    dailyTodo = 0;
                }else if(task.getDailyTradingVolume()==dailyTodo){
                    dailyTodo = 0;
                    task.setFpValue(task.getDailyTradingVolume());
                    tasks.add(task);
                    dayTasksAll.removeIf(item->item.getTaskId().equals(day.getTaskId()));
                }else {
                    dailyTodo = dailyTodo-task.getDailyTradingVolume();
                    task.setFpValue(task.getDailyTradingVolume());
                    tasks.add(task);
                    dayTasksAll.removeIf(item->item.getTaskId().equals(day.getTaskId()));
                }
            }
            List<PandaTask> reservedTasks = new ArrayList<>(reservedTasksAll);
            for(PandaTask day:reservedTasks){
                if(reserveddo<=0){
                    break;
                }
                if(day.getReservedTradingVolume()<=0){
                    continue;
                }
                PandaTask task =  new PandaTask();
                task = JSON.parseObject(JSON.toJSONBytes(day),PandaTask.class);

                task.setDailyTradingVolume(0);
                if(task.getReservedTradingVolume()>reserveddo){
                    task.setFpValue(reserveddo);
                    reserveTasks.add(task);
                    int finalReserveddo = reserveddo;
                    reservedTasksAll.forEach(item->{
                        if(item.getTaskId().equals(day.getTaskId()) ){
                            item.setReservedTradingVolume(day.getReservedTradingVolume()- finalReserveddo);
                        }
                    });
                    reserveddo =0;
                }else if(task.getReservedTradingVolume()==reserveddo){
                    reserveddo =0;
                    task.setFpValue(task.getReservedTradingVolume());
                    reserveTasks.add(task);
                    reservedTasksAll.removeIf(item->item.getTaskId().equals(day.getTaskId()));
                }else {
                    reserveddo =reserveddo -task.getReservedTradingVolume();
                    task.setFpValue(task.getReservedTradingVolume());
                    reserveTasks.add(task);
                    reservedTasksAll.removeIf(item->item.getTaskId().equals(day.getTaskId()));
                }
            }
            List<Long> dayTaskIds = tasks.stream().map(PandaTask::getTaskId).collect(Collectors.toList());
            List<Long> reserveTasksIds = reserveTasks.stream().map(PandaTask::getTaskId).collect(Collectors.toList());
            // 剩余未分配的处理
            if(i==sysUsers.size()){
                dayTasksAll.forEach(item->{
                    if(dayTaskIds.contains(item.getTaskId())){
                        tasks.forEach(task->{
                            if(item.getTaskId().equals(task.getTaskId())){
                                task.setFpValue(task.getFpValue()+item.getDailyTradingVolume());
                            }
                        });
                    }else {
                        item.setReservedTradingVolume(0);
                        item.setFpValue(item.getDailyTradingVolume());
                        tasks.add(item);
                    }

                });
                reservedTasksAll.forEach(item->{
                    if(reserveTasksIds.contains(item.getTaskId())){
                        reserveTasks.forEach(task->{
                            if(item.getTaskId().equals(task.getTaskId())){
                                task.setFpValue(task.getFpValue()+item.getReservedTradingVolume());
                            }
                        });
                    }else {
                        item.setDailyTradingVolume(0);
                        item.setFpValue(item.getReservedTradingVolume());
                        reserveTasks.add(item);
                    }
                });
            }
            // 汇总当天单预留单任务
            Map<String,PandaTask> taskMap =new HashMap<>();
            for(PandaTask res:reserveTasks){
                taskMap.put(Long.toString(res.getTaskId()),res);
            }
            Set<String> reserveTaskId =taskMap.keySet();
            List<String> reserveTaskIds = new ArrayList<>(reserveTaskId);
            reserveTaskIds.removeIf(item->dayTaskIds.contains(Long.valueOf(item)));
            List<PandaTask> countTasks = new ArrayList<>();
            tasks.forEach(dayTask->{
                dayTask.setDailyTradingVolume(dayTask.getFpValue());
                PandaTask reserveTask = taskMap.get(Long.toString(dayTask.getTaskId()));
                if(reserveTask!=null ){
                    dayTask.setReservedTradingVolume(reserveTask.getFpValue());
                }
                countTasks.add(dayTask);
            });
            reserveTasks.forEach(reservedTask->{
                if(reserveTaskIds.contains(String.valueOf(reservedTask.getTaskId()))){
                    reservedTask.setReservedTradingVolume(reservedTask.getFpValue());
                    countTasks.add(JSON.parseObject(JSON.toJSONString(reservedTask),PandaTask.class));
                }
            });
            distributionTaskToUser(user, countTasks);
        }
    }

    private PandaWorkbench createTodo(PandaTask item,SysUser sysUser){
        PandaWorkbench workbench= new PandaWorkbench();
        workbench.setLinkId(item.getTaskId());
        workbench.setLinkTable(Constants.TABLE_TASK);
        workbench.setType(EnumConstants.TodoType.TASK_OPERATION.getCode());
        String day = DateFormatUtils.format(item.getTastDate(), "yyyy-MM-dd");

        StringBuilder sb = new StringBuilder();
        sb.append("【操作任务】").append(item.getTaskName()).append("-").append(day);
        workbench.setName(sb.toString());
        workbench.setUserId(sysUser.getUserId());

        workbench.setStatus(EnumConstants.SysStatus.OPEN.getCode());

        workbench.setExts1("1");

        TPandaTaskUser tPandaTaskUser = new TPandaTaskUser();
        tPandaTaskUser.setLinkId(String.valueOf(item.getTaskId()));
        tPandaTaskUser.setType(EnumConstants.TodoType.TASK_OPERATION.getCode());
        tPandaTaskUser.setResponsibleUserId(sysUser.getUserId());
        tPandaTaskUser.setStatus(EnumConstants.SysStatus.OPEN.getCode());
        tPandaTaskUser.setName(sb.toString());
        tPandaTaskUser.setDailyTradingVolume(item.getDailyTradingVolume());
        tPandaTaskUser.setReservedTradingVolume(item.getReservedTradingVolume());
        taskUserService.insertTPandaTaskUser(tPandaTaskUser);
        workbench.setExts5(String.valueOf(tPandaTaskUser.getId()));
        workbenchService.insertPandaWorkbench(workbench);
        // 生成消息通知
        workbenchService.createTodoNotice(workbench);
        return workbench;
    }
}
